﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Data;
using System.Dynamic;
using System.Collections;

namespace DynamicToSql
{
    public interface IStatement
    {
        TValue ToScalar<TValue>();
        
        IList<dynamic> ToList();
        
        IList<IList<dynamic>> ToMultipleList();
        
        int Execute();

        IEnumerable<KeyValuePair<string, IParameter>> GetParameters();

        IStatement Parameter(string name, object value);

        IStatement Parameter(string name, object value, DbType type, ParameterDirection direction);

        ISession Session { get; }

        StatementType Type { get; }

        string Sql { get; }

        IParameter this[string name] { get; }
    }

    internal sealed class Statement : IStatement
    {
        private IParameterCollection parameters;

        private Statement()
        { 
        
        }

        internal Statement(ISession session, string sql)
            :this(session, sql, StatementType.Sql)
        {
  
        }

        internal Statement(ISession session, string sql, StatementType type)
        {
            this.Session = session;
            this.Type = type;
            this.Sql = sql;
            this.parameters = new ParameterCollection();
        }

        public TValue ToScalar<TValue>()
        {
            return StatementHelper.ToScalar<TValue>(this);
        }

        public IList<dynamic> ToList()
        {
            return StatementHelper.ToList(this);
        }

        public IList<IList<dynamic>> ToMultipleList()
        {
            return StatementHelper.ToMultipleList(this);
        }

        public int Execute()
        {
            return StatementHelper.Execute(this);
        }

        public IEnumerable<KeyValuePair<string, IParameter>> GetParameters()
        {
            return parameters;
        }

        public IStatement Parameter(string name, object value)
        {
            this.parameters[name] = new Parameter(name, value);
            return this;
        }

        public IStatement Parameter(string name, object value, DbType type, ParameterDirection direction)
        {
            this.parameters[name] = new Parameter(name, value, type, direction);
            return this;
        }

        public IParameter this[string name]
        {
            get { return this.parameters.ContainsKey(name) ? this.parameters[name] : null; }
        }

        public ISession Session { get; private set; }

        public StatementType Type { get; private set; }

        public string Sql { get; private set; }
    }
}
